Using Interact¶
The interact
function (ipywidgets.interact
) automatically
creates user interface (UI) controls for exploring code and data
interactively. It is the easiest way to get started using IPython’s
widgets.
In [1]:
from __future__ import print_function
from ipywidgets import interact, interactive, fixed
import ipywidgets as widgets
As of ipywidgets 5.0, only static images of the widgets in this notebook will show on http://nbviewer.ipython.org. To view the live widgets and interact with them, you will need to download this notebook and run it with a Jupyter Notebook server.
Basic interact
¶
At the most basic level, interact
autogenerates UI controls for
function arguments, and then calls the function with those arguments
when you manipulate the controls interactively. To use interact
, you
need to define a function that you want to explore. Here is a function
that prints its only argument x
.
In [2]:
def f(x):
return x
When you pass this function as the first argument to interact
along
with an integer keyword argument (x=10
), a slider is generated and
bound to the function parameter.
In [3]:
interact(f, x=10);
10
When you move the slider, the function is called, which prints the
current value of x
.
If you pass True
or False
, interact
will generate a
checkbox:
In [4]:
interact(f, x=True);
True
If you pass a string, interact
will generate a text area.
In [5]:
interact(f, x='Hi there!');
'Hi there!'
interact
can also be used as a decorator. This allows you to define
a function and interact with it in a single shot. As this example shows,
interact
also works with functions that have multiple arguments.
In [6]:
@interact(x=True, y=1.0)
def g(x, y):
return (x, y)
(True, 1.0)
Fixing arguments using fixed
¶
There are times when you may want to explore a function using
interact
, but fix one or more of its arguments to specific values.
This can be accomplished by wrapping values with the fixed
function.
In [7]:
def h(p, q):
return (p, q)
When we call interact
, we pass fixed(20)
for q to hold it fixed
at a value of 20
.
In [8]:
interact(h, p=5, q=fixed(20));
(5, 20)
Notice that a slider is only produced for p
as the value of q
is
fixed.
Widget abbreviations¶
When you pass an integer-valued keyword argument of 10
(x=10
) to
interact
, it generates an integer-valued slider control with a range
of \([-10,+3\times10]\). In this case, 10
is an abbreviation
for an actual slider widget:
IntSlider(min=-10,max=30,step=1,value=10)
In fact, we can get the same result if we pass this IntSlider
as the
keyword argument for x
:
In [9]:
interact(f, x=widgets.IntSlider(min=-10,max=30,step=1,value=10));
10
This examples clarifies how interact
proceses its keyword arguments:
- If the keyword argument is a
Widget
instance with avalue
attribute, that widget is used. Any widget with avalue
attribute can be used, even custom ones. - Otherwise, the value is treated as a widget abbreviation that is converted to a widget before it is used.
The following table gives an overview of different widget abbreviations:
Keyword argument | Widget |
| Checkbox |
| Text |
| IntSlider |
| FloatSlider |
| Dropdown |
Note that a dropdown is used if a list or a dict is given (signifying discrete choices), and a slider is used if a tuple is given (signifying a range).
You have seen how the checkbox and textarea widgets work above. Here, more details about the different abbreviations for sliders and dropdowns are given.
If a 2-tuple of integers is passed (min,max)
, an integer-valued
slider is produced with those minimum and maximum values (inclusively).
In this case, the default step size of 1
is used.
In [10]:
interact(f, x=(0,4));
2
If a 3-tuple of integers is passed (min,max,step)
, the step size can
also be set.
In [11]:
interact(f, x=(0,8,2));
4
A float-valued slider is produced if the elements of the tuples are
floats. Here the minimum is 0.0
, the maximum is 10.0
and step
size is 0.1
(the default).
In [12]:
interact(f, x=(0.0,10.0));
5.0
The step size can be changed by passing a third element in the tuple.
In [13]:
interact(f, x=(0.0,10.0,0.01));
5.0
For both integer and float-valued sliders, you can pick the initial
value of the widget by passing a default keyword argument to the
underlying Python function. Here we set the initial value of a float
slider to 5.5
.
In [14]:
@interact(x=(0.0,20.0,0.5))
def h(x=5.5):
return x
5.5
Dropdown menus are constructed by passing a tuple of strings. In this case, the strings are both used as the names in the dropdown menu UI and passed to the underlying Python function.
In [15]:
interact(f, x=['apples','oranges']);
'apples'
If you want a dropdown menu that passes non-string values to the Python function, you can pass a dictionary. The keys in the dictionary are used for the names in the dropdown menu UI and the values are the arguments that are passed to the underlying Python function.
In [16]:
interact(f, x={'one': 10, 'two': 20});
10
Using function annotations with interact
¶
If you are using Python 3, you can also specify widget abbreviations using function annotations.
Define a function with a checkbox widget abbreviation for the argument
x
.
In [17]:
def f(x:True): # python 3 only
return x
Then, because the widget abbreviation has already been defined, you can
call interact
with a single argument.
In [18]:
interact(f);
True
If you are running Python 2, function annotations can be defined using
the @annotate
function.
In [19]:
from IPython.utils.py3compat import annotate
In [20]:
@annotate(x=True)
def f(x):
return x
In [21]:
interact(f);
True
interactive
¶
In addition to interact
, IPython provides another function,
interactive
, that is useful when you want to reuse the widgets that
are produced or access the data that is bound to the UI controls.
Here is a function that returns the sum of its two arguments.
In [22]:
def f(a, b):
return a+b
Unlike interact
, interactive
returns a Widget
instance
rather than immediately displaying the widget.
In [23]:
w = interactive(f, a=10, b=20)
The widget is a Box
, which is a container for other widgets.
In [24]:
type(w)
Out[24]:
ipywidgets.widgets.interaction.interactive
The children of the Box
are two integer-valued sliders produced by
the widget abbreviations above.
In [25]:
w.children
Out[25]:
(<ipywidgets.widgets.widget_int.IntSlider at 0x108047be0>,
<ipywidgets.widgets.widget_int.IntSlider at 0x1080537b8>,
<ipywidgets.widgets.widget_output.Output at 0x1080479e8>)
To actually display the widgets, you can use IPython’s display
function.
In [26]:
from IPython.display import display
display(w)
30
At this point, the UI controls work just like they would if interact
had been used. You can manipulate them interactively and the function
will be called. However, the widget instance returned by interactive
also give you access to the current keyword arguments and return value
of the underlying Python function.
Here are the current keyword arguments. If you rerun this cell after manipulating the sliders, the values will have changed.
In [27]:
w.kwargs
Out[27]:
{'a': 10, 'b': 20}
Here is the current return value of the function.
In [28]:
w.result
Out[28]:
30
Disabling continuous updates¶
When interacting with long running functions, realtime feedback is a burden instead of being helpful. See the following example:
In [29]:
def slow_function(i):
print(int(i),list(x for x in range(int(i)) if
str(x)==str(x)[::-1] and
str(x**2)==str(x**2)[::-1]))
return
In [30]:
%%time
slow_function(1e6)
1000000 [0, 1, 2, 3, 11, 22, 101, 111, 121, 202, 212, 1001, 1111, 2002, 10001, 10101, 10201, 11011, 11111, 11211, 20002, 20102, 100001, 101101, 110011, 111111, 200002]
CPU times: user 487 ms, sys: 1.76 ms, total: 489 ms
Wall time: 488 ms
Notice that the output is updated even while dragging the mouse on the slider. This is not useful for long running functions due to lagging:
In [31]:
from ipywidgets import FloatSlider
interact(slow_function,i=FloatSlider(min=1e5, max=1e7, step=1e5))
100000 [0, 1, 2, 3, 11, 22, 101, 111, 121, 202, 212, 1001, 1111, 2002, 10001, 10101, 10201, 11011, 11111, 11211, 20002, 20102]
Out[31]:
<function __main__.slow_function>
There are two ways to mitigate this. You can either only execute on demand, or restrict execution to mouse release events.
__manual
¶
The __manual
kwarg of interact allows you to restrict execution so
it is only done on demand. A button is added to the interact controls
that allows you to trigger an execute event.
In [32]:
interact(slow_function,i=FloatSlider(min=1e5, max=1e7, step=1e5),__manual=True)
100000 [0, 1, 2, 3, 11, 22, 101, 111, 121, 202, 212, 1001, 1111, 2002, 10001, 10101, 10201, 11011, 11111, 11211, 20002, 20102]
Out[32]:
<function __main__.slow_function>
continuous_update
¶
If you are using slider widgets, you can set the continuous_update
kwarg to False
. continuous_update
is a kwarg of slider widgets
that restricts executions to mouse release events.
In [33]:
interact(slow_function,i=FloatSlider(min=1e5, max=1e7, step=1e5,continuous_update=False))
100000 [0, 1, 2, 3, 11, 22, 101, 111, 121, 202, 212, 1001, 1111, 2002, 10001, 10101, 10201, 11011, 11111, 11211, 20002, 20102]
Out[33]:
<function __main__.slow_function>
Arguments that are dependent of each other¶
Arguments that are dependent of each other can be expressed manually
using observe
. See the following example, where one variable is used
to describe the bounds of another. For more information, please see the
widget events example notebook.
In [34]:
x_widget = FloatSlider(min=0.0, max=10.0, step=0.05)
y_widget = FloatSlider(min=0.5, max=10.0, step=0.05, value=5.0)
def update_x_range(*args):
x_widget.max = 2.0 * y_widget.value
y_widget.observe(update_x_range, 'value')
def printer(x, y):
print(x, y)
interact(printer,x=x_widget, y=y_widget)
0.0 5.0
Out[34]:
<function __main__.printer>
In [ ]: